/* ** por compatibilidad se omiten tildes **
================================================================================
 TRABAJO PRACTICO 3 - System Programming - ORGANIZACION DE COMPUTADOR II - FCEN
================================================================================s
  definicion de funciones del scheduler
*/

#include "sched.h"
#include "screen.h"
#include "game.h"

static int slot_rojos[CANT_ZOMBIS];	// arreglo de manejo de slots del jugador rojo
static int slot_azules[CANT_ZOMBIS];    // arreglo de manejo de slots del jugador azul
static int slot_actual_rojo = -1;       // slot que fue seleccionado último hay zombis activos
					// del jugador rojo. Si no hay zombis activos, es -1
static int slot_actual_azul = -1;       // slot que fue seleccionado último hay zombis activos
static int actual_rojo = 1;		// del jugador rojo. Si no hay zombis activos, es -1
static int hay_zombis_rojos_activos = 0;  // flags indicando si hay zombis activos
static int hay_zombis_azules_activos = 0; // flags indicando si hay zombis actuvos


/**
* verificar_activos_rojos()
*
* se usa para actualizar el flag de zombis activos 
* rojos
*/
int verificar_activos_rojos() {
	int i = 0;
	for (i = 0; i < CANT_ZOMBIS; i++) {
		if (slot_rojos[i] != -1) {
			return 1;
		}
	}
	return 0;
}

/**
* verificar_activos_azules()
*
* se usa para actualizar el flag de zombis activos 
* rojos
*/
int verificar_activos_azules() {
	int i = 0;
	for (i = 0; i < CANT_ZOMBIS; i++) {
		if (slot_azules[i] != -1) {
			return 1;
		}
	}
	return 0;
}


/**
* desalojar_zombie_actual()
* 
* desaloja el zombie actual.
* Pone el slot en -1.
*/
void desalojar_zombie_actual() {
      if (es_actual_rojo() == 1) {
		desalojar_zombie_rojo(slot_actual_rojo);
      } else {
		desalojar_zombie_rojo(slot_actual_azul);
      }
}

/**
* desalojar_zombie_rojo(unsigned int zombi_actual)
* 
* marca el slot del zombie rojo pasado como parámetro
* como libre. y verifica si hay zombies activos.
* También deshabilita el reloj.
*
*/
void desalojar_zombie_rojo(unsigned int zombi_actual) {
	slot_rojos[zombi_actual] = -1; // marca el slot como libre
	if (verificar_activos_rojos() == 0) { // si no hay mas rojos activos
		slot_actual_rojo = -1;	     // indica que el actual no es mas rojo
		hay_zombis_rojos_activos = 0; // indica que no hay zombis azules activos
	}
	disable_reloj_zombie_rojo(zombi_actual); // deshabilita el reloj visualmente
						 
	imprimir_reloj_zombie_rojo(zombi_actual); // imprime el zombie como muerto

}

/**
* desalojar_zombie_azul(unsigned int zombi_actual)
* 
* marca el slot del zombie azul pasado como parámetro
* como libre. y verifica si hay zombies activos.
* También deshabilita el reloj.
*
*/
void desalojar_zombie_azul(unsigned int zombi_actual) {
	slot_azules[zombi_actual] = -1;  // marca el slot como libre
	if (verificar_activos_azules() == 0) { // si no hay mas rojos activos
		slot_actual_azul = -1;	       // indica que el actual no es mas rojo
		hay_zombis_azules_activos = 0; // indica que no hay zombis rojos activos
	}
	disable_reloj_zombie_azul(zombi_actual); // deshabilita el reloj visualmente
	imprimir_reloj_zombie_azul(zombi_actual); // deshabilita el reloj visualmente

}


/**
* enable_hay_zombis_activos_rojos()
* 
* se llama desde afuera del archivo para 
* habilitar el flag de que existen zombis activos 
* rojos
*
*/
void enable_hay_zombis_activos_rojos() {
	hay_zombis_rojos_activos = 1;
}

/**
* disable_hay_zombis_activos_rojos()
* 
* se llama desde afuera del archivo para 
* deshabilitar el flag de que existen zombis activos
* rojos
*/
void disable_hay_zombis_activos_rojos() {
	hay_zombis_rojos_activos = 0;
}

/**
* enable_hay_zombis_activos_azules()
* 
* se llama desde afuera del archivo para 
* habilitar el flag de que existen zombis activos 
* azules
*
*/
void enable_hay_zombis_activos_azules() {
	hay_zombis_azules_activos = 1;
}

/**
* disable_hay_zombis_activos_azules()
* 
* se llama desde afuera del archivo para 
* deshabilitar el flag de que existen zombis activos
* azules
*/
void disable_hay_zombis_activos_azules() {
	hay_zombis_azules_activos = 0;
}

/**
* obtener_slot_libre_rojo()
* obtiene el primer slot que se encuentra
* libre para asignarle a un zombi rojo que se 
* lanza por el jugador. Este es aquel
* indice del arreglo de slots que se encuentra
* en -1-
* Si no hay ninguno vacío devuelve CANT_ZOMBIS
*/
int obtener_slot_libre_rojo() {
	int i = 0;
		
	for (i = 0; i < CANT_ZOMBIS; i++) { // loop por todos los slots
		if (slot_rojos[i] == -1) {
			slot_rojos[i] = 0;
			break;
		}
	}
	return i;
}

/**
* obtener_slot_libre_azul()
* obtiene el primer slot que se encuentra
* libre para asignarle a un zombi azul que se 
* lanza por el jugador. Este es aquel
* indice del arreglo de slots que se encuentra
* en -1-
* Si no hay ninguno vacío devuelve CANT_ZOMBIS
*/

int obtener_slot_libre_azul() {
	int i = 0;
	
	for (i = 0; i < CANT_ZOMBIS; i++) {
		if (slot_azules[i] == -1) {
			slot_azules[i] = 0;
			break;
		}
	}
	return i;
}
/**
* obtener_zombi_actual_rojo()
* devuelve el ultimo zombi
* rojo elegido por el scheduler
* si hay zombis rojos a
* activos
*/
int obtener_zombi_actual_rojo() {
	return slot_actual_rojo;
}

/**
* obtener_zombi_actual_azul()
* devuelve el ultimo zombi
* azul elegido por el scheduler
* si hay zombis rojos a
* activos
*/
int obtener_zombi_actual_azul() {
	return slot_actual_azul;
}

/**
* es_actual_rojo()
*
* devuelve si la última
* tarea que escogió el scheduler
* es del jugador rojo
*/
int es_actual_rojo() {
	return actual_rojo;
}

/**
* unsigned short sched_proximo_indice_rojo()
* 
* devuelve el índice de la GDT de la próxima
* tarea a ejecutar en caso de que sea
* el turno del procesador del jugador rojo.
*/
unsigned short sched_proximo_indice_rojo() {
	if (hay_zombis_rojos_activos == 0 || es_juego_terminado() == 1 || esta_mostrando_excepcion() == 1) {
		return GDT_IDX_IDLE*8;
 	} 
	int i = slot_actual_rojo+1;

	if (i == CANT_ZOMBIS) {
		i = 0;
	}
	while (i != slot_actual_rojo) {
		if (i == CANT_ZOMBIS) {
			i = 0;
		}

		if (slot_rojos[i] != -1) {
			slot_actual_rojo = i;
			return (GDT_IDX_ROJO_1 + i)*8;
		}
		i++;
	}
	if (slot_rojos[slot_actual_rojo] != -1) {
			return (GDT_IDX_ROJO_1 + slot_actual_rojo)*8;
	}

 	return GDT_IDX_IDLE*8;
}

/**
* unsigned short sched_proximo_indice_azul()
* 
* devuelve el índice de la GDT de la próxima
* tarea a ejecutar en caso de que sea
* el turno del procesador del jugador azul.
*/

unsigned short sched_proximo_indice_azul() {
	if (hay_zombis_azules_activos == 0 || es_juego_terminado() == 1) {
		return GDT_IDX_IDLE*8;
 	} 

	int i = slot_actual_azul+1;

	if (i == CANT_ZOMBIS) {
		i = 0;
	}
	while (i != slot_actual_azul) {
		if (i == CANT_ZOMBIS) {
			i = 0;
		}

		if (slot_azules[i] != -1) {
			slot_actual_azul = i;
			return (GDT_IDX_AZUL_1 + i)*8;
		}
		i++;
	}

	if (slot_azules[slot_actual_azul] != -1) {
			return (GDT_IDX_AZUL_1 + slot_actual_azul)*8;
	}

 	return GDT_IDX_IDLE*8;

}
/**
* sched_idle()
* devuelve el índice de la GDT
* de la tarea IDLE
*/
unsigned short sched_idle() {
	return GDT_IDX_IDLE*8;
}
/**
* sched_proximo_indice()
*
* devuelve el índice de la GDT de la próxima
* tarea
*/

unsigned short sched_proximo_indice() {
	int retorno = 0;

	reducir_tiempo_prudencial(); // reduce el tiempo prudencial
				     // es decir el tiempo que
				     // tarda el juego en considerarse
				     // terminado si no sucede nada

	// si no hay ni rojos ni azules a lanzar y no están activos en 
	// el mapa se termina el juego
	if (dame_restantes_rojo() == 0 && dame_restantes_azul() == 0
	    && hay_zombis_rojos_activos == 0 && hay_zombis_azules_activos == 0) {
		terminar_juego();
	}

	// si transcurrió la cantidad de ciclos prudenciales sin que suceda
	// nada se terminó el juego
	if (dame_tiempo_prudencial() == 0)
	    terminar_juego();
	
	if (actual_rojo == 0) {
		actual_rojo = 1;
		retorno = sched_proximo_indice_rojo(); 
	} else {
		actual_rojo = 0;
		retorno = sched_proximo_indice_azul();	
	}	
 	return retorno;

}

/**
* sched_inicializar()
*
* inicializa el scheduler
*/
void sched_inicializar() {
	int i = 0;
	for (i = 0; i < CANT_ZOMBIS; i++) {
		slot_rojos[i] = -1;
		slot_azules[i] = -1;
	}
}

